/**
 * @file JSONNode.h
 */
#ifndef _JSONNODE_H_
#define _JSONNODE_H_

#include "../collections/tree/MCTreeNode.h"
#include "../collections/LinkedHashtableT.h"
#include "../text/CFString.h"

namespace cppflib
{

namespace json
{

class JSONObject;
class JSONArray;

/**
 *  A class which represents a node in JSONDocument (JSONObject or JSONArray).
 *  Super class of JSONObject and JSONArray
 */
class _DLLAPI JSONNode : public collections::tree::MCTreeNode
{
public:
    typedef enum
    {
       JN_OBJECT,
       JN_ARRAY
    } nodetype_t;

    typedef enum
    {
       JVL_NONE,   // not one of value type

       JVL_STRING,
       JVL_INT32,
       JVL_INT64,
       JVL_DOUBLE,
       JVL_OBJECT,
       JVL_ARRAY,
       JVL_BOOLEAN,
       JVL_NULL
    } valuetype_t;

protected:
    JSONNode(void);
    PUBLIC valuetype_t GetValueType(BaseObject *pVal);

public:
	virtual ~JSONNode(void);

    /////// derived from MCTreeNode
    virtual MCTreeNode * GetChild(u32_t index);
    virtual MCTreeNode * GetChild(const BaseObject &key);
    virtual bool AddChild(MCTreeNode * pChild);
    virtual bool DeleteChild(const BaseObject &key);
    virtual bool IsAncestor(MCTreeNode *pNode);
    virtual bool Move(MCTreeNode *pNode);
    virtual void DetachFromTree();

    /////// newly added
    virtual nodetype_t GetNodeType() = 0;
    virtual valuetype_t GetValueType(u32_t index) = 0;
    virtual JSONObject * CastToJSONObject() = 0;
    virtual JSONArray * CastToJSONArray() = 0;
};

/**
 *  JSONObject
 *
 *  Only those values which are a JSONObject or JSONArray will be a child of
 *  this JSONObject. Thus, the value returned by 
 *  MCTreeNode::GetDirectChildCount and JSONObject::GetNumberOfNameValuePairs
 *  are *different*.
 */
class _DLLAPI JSONObject : public JSONNode
{
private:
    collections::LinkedHashtableT<CFString, BaseObject> * pNVPairList;

private:
    /////// derived from JSONNode
    virtual JSONNode::nodetype_t GetNodeType();
    virtual JSONObject * CastToJSONObject();
    virtual JSONArray * CastToJSONArray();

public:
    JSONObject(void);
    virtual ~JSONObject(void);

    /////// derived from JSONNode
    virtual JSONNode::valuetype_t GetValueType(u32_t index);
    
    /////// newly added
    // Get methods
    JSONNode::valuetype_t GetValueType(const CFString& name);
    sz_t GetNumberOfNameValuePairs();

    BaseObject * Get(u32_t index);
    BaseObject * Get(const CFString& name);
    CFString * GetString(const CFString& name);
    bool GetBoolean(const CFString& name);
    double GetDouble(const CFString& name);
    int GetInt32(const CFString& name);
    i64_t GetInt64(const CFString& name);
    JSONObject * GetJSONObject(const CFString& name);
    JSONArray * GetJSONArray(const CFString& name);
    
    bool Contains(const CFString& name);
    bool IsNull(const CFString& name);

    // Set methods
    void Set(CFString *pName, CFString *pVal);
    void Set(CFString *pName, bool val);
    void Set(CFString *pName, double val);
    void Set(CFString *pName, int val);
    void Set(CFString *pName, i64_t val);
    void Set(CFString *pName, JSONObject *pJObj);
    void Set(CFString *pName, JSONArray *pJArray);
    void SetNull(CFString *pName);

    bool Remove(const CFString& name);
    bool Remove(u32_t index);
};

/**
 *  JSONArray
 */
class _DLLAPI JSONArray : public JSONNode
{
private:
    collections::ListCppObjT<BaseObject> * pValList;

private:
    /////// derived from JSONNode
    virtual JSONNode::nodetype_t GetNodeType();
    virtual JSONObject * CastToJSONObject();
    virtual JSONArray * CastToJSONArray();

public:
    JSONArray(void);
    virtual ~JSONArray(void);

    /////// derived from JSONNode
    virtual JSONNode::valuetype_t GetValueType(u32_t index);
    
    /////// newly added
    // Get methods
    BaseObject * Get(u32_t index);
    sz_t GetNumberOfValues();

    CFString * GetString(u32_t index);
    bool GetBoolean(u32_t index);
    double GetDouble(u32_t index);
    int GetInt32(u32_t index);
    i64_t GetInt64(u32_t index);
    JSONObject * GetJSONObject(u32_t index);
    JSONArray * GetJSONArray(u32_t index);

    bool IsNull(u32_t index);

    // Append methods
    void Append(CFString *pVal);
    void Append(bool val);
    void Append(double val);
    void Append(int val);
    void Append(i64_t val);
    void Append(JSONObject *pJObj);
    void Append(JSONArray *pJArray);
    void AppendNull();

    bool Remove(u32_t index);
};

} // end of namespace json

} // end of namespace cppflib


#endif

